Merged
Conversation
branchseer
commented
Mar 19, 2026
Brooooooklyn
approved these changes
Mar 20, 2026
ee4af3d to
1d7f67f
Compare
fspy's LD_PRELOAD-based file tracking does not work with statically-linked musl binaries. This disables fspy inference at execution time on musl targets while keeping plan-level config consistent across all targets. - Disable path_accesses tracking in execute_spawn when target_env is musl - Add `requires_fspy` field to e2e test config to skip fspy-dependent tests - Add dedicated musl test job (x86_64-unknown-linux-musl) in CI https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
On musl targets, LD_PRELOAD-based file tracking is not available because musl does not support cdylib. Instead, always use seccomp+unotify for file access tracking which works with all binary types. - Exclude fspy_preload_unix from musl builds (cdylib not supported) - Always use seccomp path in spawn/linux on musl (skip ELF/LD_PRELOAD check) - Add dedicated test-musl CI job (x86_64-unknown-linux-musl) - Temporarily disable other CI jobs for faster iteration https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
On musl targets, LD_PRELOAD-based file tracking is not available because musl does not support cdylib. Instead, always use seccomp+unotify for file access tracking which works with all binary types. Changes: - Exclude fspy_preload_unix from musl builds (cdylib not supported) - Remove preload_path field from Payload on musl - Always use seccomp path in spawn/linux on musl (skip ELF/LD_PRELOAD check) - Fix ioctl request type mismatch (c_ulong vs Ioctl) for musl compatibility - Add statx, access, faccessat, faccessat2 syscall handlers to seccomp filter for complete file access tracking without LD_PRELOAD - Add dedicated test-musl CI job (x86_64-unknown-linux-musl) https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
Use an Alpine Linux container for the musl test job so tests run with musl as the native libc. This avoids cross-compilation issues with static musl binaries where ctor's .init_array entries are dropped. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The .cargo/config.toml sets rustflags with a zig linker wrapper for musl targets. Override via env var to use the system cc in Alpine. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
Use sed to strip musl target linker config from .cargo/config.toml since Alpine's system cc is already musl-based. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
NativeStr and ensure_env are only used in the LD_PRELOAD code path. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
On musl, the artifact module (preload library writing) and NativeStr import are unused since LD_PRELOAD is not available. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The ctor crate's #[ctor] inside macro expansions doesn't work on musl targets because the .init_array entry is dropped by the linker. Replace with a two-part approach: - Use linkme distributed_slice to register subprocess handlers (works reliably on all targets since it uses custom linker sections) - Use a crate-level subprocess_dispatch_ctor!() macro that each test crate calls at crate scope (not inside a function) for the #[ctor] dispatcher Each crate that uses command_for_fn! must now also call subprocess_dispatch_ctor!() at crate scope. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
- Add cargo-shear ignore for ctor and linkme in subprocess_test - Use --security-opt seccomp=unconfined for Alpine container since fspy uses seccomp user notifications https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
ctor 0.6 generates .init_array entries that get dropped by the linker on musl targets. ctor 0.2 uses a different code generation approach that works reliably across all targets. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The ctor issue on musl is fundamental — neither v0.2 nor v0.6 works in Alpine containers. The .init_array entries are dropped regardless of ctor version. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
On musl targets, `std::env::args()` returns empty during `.init_array` constructors because the Rust runtime hasn't initialized its argument storage yet. This caused `subprocess_dispatch()` and `init_impl()` to silently skip subprocess dispatch, making all subprocess-based tests fail (fspy, pty_terminal, fspy_shared IPC tests). Fix by falling back to reading `/proc/self/cmdline` directly via raw libc calls when `std::env::args()` is empty. The libc-level open/read calls work during `.init_array` even when the Rust runtime isn't ready. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The previous implementation filtered out empty strings from cmdline args, but empty args are valid (e.g., `()` encodes to empty base64). This caused subprocess dispatch to fail for tests using unit arg type because the arg count dropped below 3. Now only removes the trailing empty string from the final null terminator instead of all empty strings. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
On musl/seccomp targets, `std::fs::read_dir()` opens the directory with `O_DIRECTORY` but doesn't call `getdents64` until the iterator is consumed. The seccomp handler only set READ_DIR on `getdents64` notifications, so lazy `read_dir()` calls were tracked as READ instead of READ_DIR. Fix by detecting the `O_DIRECTORY` flag in the open/openat handler and adding `READ_DIR` to the access mode. This matches the behavior of the LD_PRELOAD interceptor on glibc targets. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
Root cause: vite_task explicitly disabled fspy on musl targets (`!cfg!(target_env = "musl")`), not realizing that seccomp unotify provides equivalent file access tracing to LD_PRELOAD. This caused all cache invalidation to fail on musl since file accesses were never recorded. Additional fixes: - Set CC env vars for musl cross-compilation so cc-rs can find the zig CC wrapper (fixes stackalloc build failure) - Use openat(AT_FDCWD) instead of open() in seccomp arg_types test because musl's open() uses the native `open` syscall on x86_64, which isn't intercepted by the test's openat-only handler - Refactor shm_io test to use subprocess_test infrastructure instead of raw #[ctor] (fixes musl args unavailability during .init_array) - Add required-features to fspy_seccomp_unotify arg_types test so it only compiles when supervisor+target features are available https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
- Strip [env] section in CI musl job alongside [target.*musl] sections, since the CC_*_musl env vars point to the zigcc wrapper which isn't available on native Alpine (system gcc is used instead) - Add ctor to cargo-shear ignored list in fspy_shared since it's used transitively through the subprocess_dispatch_ctor!() macro https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
Alpine's Node.js 22.15.1 package doesn't enable TypeScript type stripping by default, causing ERR_UNKNOWN_FILE_EXTENSION errors when running the .ts test tool scripts. Set NODE_OPTIONS to enable --experimental-strip-types explicitly. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The E2E test harness clears env vars and only passes PATH, NO_COLOR, TERM. On Alpine musl CI, NODE_OPTIONS=--experimental-strip-types is needed for .ts test tools. Inherit NODE_OPTIONS when present. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
Alpine's Node.js package (v22.15.1) is compiled without TypeScript type-stripping support (ERR_NO_TYPESCRIPT). Install the official Node.js musl binary from unofficial-builds.nodejs.org which includes full TypeScript support needed by the test tool scripts (.ts files). https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The 'latest-v22.x' URL pattern doesn't exist on unofficial-builds. Query the index.json to find the latest v22 version and use the specific version URL to download the musl binary. https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
- Remove speculative seccomp comment from CI workflow - Use .node-version file for Node.js version in Alpine CI - Remove [env] CC wrapper vars from .cargo/config.toml and CI sed - Revert O_DIRECTORY check in seccomp handler; instead consume a dir entry in the rust_std test so getdents64 fires - Fix misleading "musl does not support cdylib" comment; update fspy README with musl section - Revert to plain #[ctor::ctor] in command_for_fn! macro; remove linkme distributed slice infrastructure and subprocess_dispatch_ctor - Keep /proc/self/cmdline fallback for musl arg reading in init_impl - Remove all requires_fspy from snapshot toml files and Rust code https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
The seccomp override is no longer needed since fspy seccomp tracing was fixed for musl in a prior commit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ker scripts - Use node:22-alpine3.21 image instead of alpine:3.21 to get Node.js with TypeScript support pre-installed - Use corepack to install pnpm, respecting packageManager in package.json - Update .cargo linker scripts to detect Linux hosts and use system cc directly, removing the need for the sed workaround in CI - Split Rust setup into rustup install + toolchain install from rust-toolchain.toml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tion The linker path specified via rustflags (-C linker=...) is passed to rustc which doesn't resolve it relative to the config file. Using Cargo's native `linker` key resolves relative paths correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nv override - Replace raw libc::open/read/close with safe nix equivalents in read_proc_cmdline - Remove CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS env var from Alpine CI — the linker scripts detect Linux and use system cc directly - Revert linker config to rustflags (needed for cargo-zigbuild bindeps) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1d7f67f to
29bfaa0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
test-muslCI job that runs the full test suite againstx86_64-unknown-linux-muslhttps://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv